<?php namespace pft\Order;
/**
 * Created by PhpStorm.
 * User: cgp
 * Date: 14-2-11
 * Time: 下午5:44
 * 重写孙泽的DisOrder.php文件
 */

/**
 *下单基类
 *通过调用order()完成下单流程
 */
use pft\Exception\MsgException;
use pft\Exception\InterFaceException;
use pft\Exception\DisOrderException;
use pft\Member;
use pft\Prod\ProductInfo;

class SzOrder{

    /**
     *票付通内部接口对象
     *@var object
     */
    public $s;

    /**
     *产品下单信息
     *@var array
     */
    public $option;//订单参数

    /**
     *产品信息类ProductInfo对象，查询产品信息和分销价格
     *@var object
     */
    public $p;//产品

    /**
     *会员类Member对象,查询账户余额
     *@var object
     */
    public $m;//分销商

    /**
     *是否零售
     *@var int 0不零售1零售
     */
    private $sale;

    /**
     *下单方式
     *@var int 0正常下单1普通用户下单按零售价
     */
    private $ordermode;
    /**
     * 数据库连接
     * @var object
     */
    private $db;

    const MODE_DIS  = 0;
    const NOT_SALE  = 0;

    const MODE_SALE = 1;
    const IS_SALE = 1;


    /**
     *
     *@param object $db 数据库连接对象
     *@param object $s 票付通内部接口对象
     *@param object $p 产品ProductInfo对象
     *@param object $m 会员Member对象
     *@param int $ordermode 下单方式
     *@param int $sale 是否零售
     */
    public function __construct($db,\SoapClient $s,ProductInfo $p,Member $m,$ordermode,$sale){
        $this->db = $db;
        $this->s=$s;
        $this->p=$p;
        $this->m=$m;
        $this->ordermode=$ordermode;
        $this->sale=$sale;
    }

    /**
     *@param array $option 下单参数
     *@return int $r 成功返回主6位数订单号，失败返回-100
     */
    public function order($option){
        $this->option   = $option;
        $member         = $this->m->memberID;
        $pid            = $this->p->pid;

        $begintime      = $option['begintime'];
        $ordername      = $option['ordername'];
        $ordertel       = $option['ordertel'];
        $contacttel     = $option['contacttel'];
        $tnum           = $option['tnum'];
        $remoteorder    = $option['remoteorder'];
        $paymode        = $option['paymode'];

        $p_info = $this->p->pInfo();

        $ptitle = $p_info['ltitle'].$p_info['ttitle'];
        $endtime=($p_info['delaydays']-1)<0?0:($p_info['delaydays']-1);
        $time=strtotime($begintime)+$endtime*24*3600;
        $endtime=date("Y-m-d",$time);
        $begintime.=" 00:00:00";
        $endtime.=" 23:59:59";

        /*产品预订检查*/
        $totalMoney = 0;
        $tprice     = $this->p->tPrice($member,$begintime,$this->sale);
//        echo 'tprice= ' . $tprice;
        $totalTprice = $tprice*$tnum;
        $totalMoney += $totalTprice;
        $smsSend    =0;
        $reSendMsg  =1;
        $pcode      =0;
        $ordermode  =$this->ordermode;
        if ($paymode==1){
            $smsSend=1;
            $reSendMsg=0;
        }
        if ($p_info['p_type']=="B") {/*线路产品额外信息*/
            $playdateStr=explode("-",substr($begintime,0,10));
            $playdateStr=substr($playdateStr[0],2,2).$playdateStr[1].$playdateStr[2];
            $series=preg_replace('/{fck_date}/',$playdateStr,$p_info['series_model']);         //团号
            $assembly=abs($option['assembly']);//集合地点
        }
        $proInfos=array();
        $c_infos=array();
        if ( $p_info['p_type']=="C" ){//酒店按联票产品下单
            $leavetime = $option['leavetime'];
            $days=ceil((strtotime($leavetime)-strtotime($begintime))/24/3600);
            $cpro=new ProductInfo($p_info['pid'], $this->s, $this->db);
            for($n=1;$n<$days;$n++){
                try{
                    $date=date("Y-m-d",strtotime($begintime)+3600*24*$n);
                    $c_tprice=$cpro->tPrice($member,$begintime,$this->sale);
                    $c_tnum=$tnum;
                    $endtime=$date." 23:59:59";
                    $c_infos[]=array("member"=>$member,
                        "tprice"=>$c_tprice,
                        "tnum"=>$c_tnum,
                        "ltitle"=>$p_info['ltitle'],
                        "ttitle"=>$p_info['ttitle'],
                        "pid"=>$p_info['pid'],
                        "lid"=>$p_info['lid'],
                        "tid"=>$p_info['tid'],
                        "begintime"=>$date." 00:00:00",
                        "endtime"=>$date." 23:59:59",
                        "storage"=>$p_info['storage'],
                        "storage_open"=>$p_info['storage_open'],
                        "salerid"=>$p_info['salerid'],
                        "ordername"=>$ordername,
                        "ordertel"=>$ordertel,
                        "paymode"=>$paymode,
                        "ordermode"=>$ordermode,
                        "apply_did"=>$p_info['apply_did'],
                        "sapply_did"=>$p_info['sapply_did']);
                    $totalMoney+=$c_tprice*$c_tnum;
                }catch(\Exception $e){
                }
            }
        }
        elseif($p_info['p_type']=="F"){//套票产品
            $pcode=1;
            $param['tnum']=$tnum;
            $param['begintime']=$begintime;
            $param['endtime']=$endtime;
            $param['ordername']=$ordername;
            $param['ordertel']=$ordertel;
            $param['member']=$member;
            $param['paymode']=$paymode;
            $param['ordermode']=$ordermode;
            $order_infos=$s_infos=$this->aOrderInfo($p_info['attribute'],$param);
        }
        else{
//            echo '<br/>+++++++++++++++是否存在联票产品+++++++++++++++++++<br/>';
            /*查看是否存在联票产品，存在的话记录联票产品下单信息*/
            foreach((array)$option['c_pids'] as $c_pid=>$c_tnum){
                if($c_tnum>0){
                    $c_pid=abs($c_pid);
//                    $cpro = new ProductInfo($c_pid, $this->s, $this->db);
                    $c_about = $this->p->pInfo($c_pid);
                    $c_tprice = $this->p->tPrice($member, $begintime, $this->sale, $c_pid);
                    $c_infos[]=array(
                        "member"=>$member,
                        "tprice"=>$c_tprice,
                        "tnum"=>$c_tnum,
                        "ltitle"=>$c_about['ltitle'],
                        "ttitle"=>$c_about['ttitle'],
                        "pid"=>$c_pid,
                        "lid"=>$c_about['lid'],
                        "tid"=>$c_about['tid'],
                        "begintime"=>$begintime,
                        "endtime"=>$endtime,
                        "storage"=>$c_about['storage'],
                        "storage_open"=>$c_about['storage_open'],
                        "salerid"=>$c_about['salerid'],
                        "ordername"=>$ordername,
                        "ordertel"=>$ordertel,
                        "paymode"=>$paymode,
                        "ordermode"=>$ordermode,
                        "apply_did"=>$c_about['apply_did'],
                        "sapply_did"=>$c_about['sapply_did']);
                    $totalMoney += $c_tprice*$c_tnum;
                }
            }
        }
        if(count($c_infos)>0){//联票购买
            $smsSend=1;
            $proInfos=$c_infos;
        }
        if(count($s_infos)>0){//套票购买
            $proInfos=$s_infos;
        }
        $proInfos[]=array(
            "member"=>$member,
            "tprice"=>$tprice,
            "tnum"=>$tnum,
            "ltitle"=>$p_info['ltitle'],
            "ttitle"=>$p_info['ttitle'],
            "pid"=>$p_info['pid'],
            "tid"=>$p_info['tid'],
            "begintime"=>$begintime,
            "endtime"=>$endtime,
            "storage"=>$p_info['storage'],
            "storage_open"=>$p_info['storage_open'],
            "sapply_did"=>$p_info['sapply_did']
        );
//        print_r($proInfos);
        $this->orderCheck($option,$p_info); //预订判定
//        echo '++++++++++++++++orderCheck+++++++++++++++++++++<br/>'.PHP_EOL;
        try{
            $this->authCheck($proInfos);        //购买权限判定
        } catch(DisOrderException $e) {
            echo $e->getMessage();
        }
        $this->storageCheck($proInfos);     //库存判定
        $this->payCheck($totalMoney);	    //金额判定
        $debug_log=<<<EOF
		Group_Order_Submit(
		"$member","{$p_info['lid']}",
		"{$p_info['tid']}","$begintime","$endtime",
		"$tprice","$tnum","$totalTprice","$ordername","$ordertel",
		"$contacttel","{$p_info['salerid']}",
		"{$p_info['sapply_did']}",$paymode,
		$ordermode,"$remoteorder",
		"$assembly","$series",
		$smsSend,0,
		$pcode);
EOF;

//        echo $debug_log;//调试变量
        $r=$this->s->Group_Order_Submit(
            $member,
            $p_info['lid'],
            $p_info['tid'],
            $begintime,
            $endtime,
            $tprice,
            $tnum,
            $totalTprice,
            $ordername,
            $ordertel,
            "$contacttel",
            $p_info['salerid'],
            $p_info['sapply_did'],
            $paymode,
            $ordermode,
            "$remoteorder",
            "$assembly",
            "$series",
            $smsSend,
            0,
            $pcode
        );
        if($r>=100000){
            /*附属产品下单*/
            if($smsSend==1){
//                print_r($c_infos);
                $this->subOrder($c_infos, $r);
                if($reSendMsg==1) $this->s->reSend_SMS_Global_PL($r,$p_info['sapply_did'],$member);//最后重发短信
            }
            /*套票产品下单*/
            if($p_info['p_type']=="F"){
                $this->appendOrder($order_infos,$r);
            }
            /*记录订单额外信息*/
            $this->appendInfo($r,$option);
            return $r;
        }
        else{
            $this->errHandle("下单接口出错,错误{$r}",$r);
        }
    }

    /**
     *联票产品下单函数.
     *完成联票产品的下单,并更新uu_order_fx_details里的订单主从关系s信息.
     *@param array 联票产品下单信息数组
     *@param int r 主订单号，用来标识附属哪个订单
     */
    public function subOrder($c_infos,$r){
        $str="update uu_order_fx_details set concat_id='$r' where orderid='$r' limit 1";
//        echo '<br/>++++++++++++subOrder++++++++++++++++<br/>';
//        echo $str;
        $this->db->query($str);
        $remoteorder = '';
        $assembly = '';
        $series = '';
        foreach($c_infos as $row){
            $c_r=$this->s->Group_Order_Submit(
                $row['member'],
                $row['lid'],
                $row['tid'],
                $row['begintime'],
                $row['endtime'],
                $row['tprice'],
                $row['tnum'],
                0,
                $row['ordername'],
                $row['ordertel'],
                $row['contacttel'],
                $row['salerid'],
                $row['sapply_did'],
                $row['paymode'],
                $row['ordermode'],
                $remoteorder,
                $assembly,
                $series,
                "1",
                "$r");
            if($c_r>=100000){
                $str="update uu_order_fx_details set concat_id='$r' where orderid='$c_r'";
//                echo '<br/>++++++++++++'.$str.'++++++++++++++++<br/>';
                $this->db->query($str);
            }else{
                $this->errHandle("附属产品下单出错",$c_r);
            }
        }
        /*
        $debug_log=<<<EOF	Group_Order_Submit("{$row['member']}","{$row['lid']}","{$row['tid']}","{$row['begintime']}","{$row['endtime']}","{$row['tprice']}","{$row['tnum']}",0,"{$row['ordername']}","{$row['ordertel']}","{$row['contacttel']}","{$row['salerid']}","{$row['apply_did']}","{$row['paymode']}","{$row['ordermode']}",$remoteorder,$assembly,$series,"1","$r");
EOF;*/
    }

    /**
     *套票产品下单函数.
     *票付通平台暂不支持.
     *@todo 如果要改为支持套票下单，完成测试工作，下函数未测试，是搬分销平台的.
     *@param array $order_infos 套票产品下单信息
     *@param int $r 套票产品下单主单号，需传如套票下单接口
     */
    public function appendOrder($order_infos,$orderId){
        $record=array("order"=>$orderId,"datetime"=>date("Y-m-d H:i:s"),"data"=>$order_infos);
        $recordStr=serialize($record);
        $errMsg=$orderId."套票附属产品下单失败";
        $acount=count($order_infos);
        $a_infos=array();
        foreach($order_infos as $row){
            $a_infos[$row['lid']][]=$row;
        }
        $ifpack=1;
        $xml=$this->s->Order_Globle_Search("","","","","","","","","","","","",
            $orderId,"","","","","",1,1,0,999,0,$stype,$payinfo,$pmode,$remotenum,
            $origin,$p_type,$order_confirm,$aid,$concat,$ifpack);
        $simplexml=simplexml_load_string($xml);
        $hasTidOrders=array();
        foreach($simplexml as $row){
            $hasTidOrders[(string)$row->UUtid]=(string)$row->UUordernum;
        }
        $count=count($simplexml);
        if($acount==($count-1)){//已下单
            return true;
        }elseif($count-1>0){//只下部分订单,进行补单
            $msg=$orderId."补单，套票附属订单数:".$acount.",实际下单数:".($count-1);
            $this->log_result($msg);
        }
        try{
            foreach($a_infos as $lid=>$aa_infos){
                $row=$aa_infos[0];
                if(array_key_exists($row['tid'],$hasTidOrders)){//该主单已经下成功
                    $ar=$hasTidOrders[$row['tid']];
                }else{
                    $ar=$this->s->Group_Order_Submit(
                        $row['member'],
                        $row['lid'],
                        $row['tid'],
                        $row['begintime'],
                        $row['endtime'],
                        $row['tprice'],
                        $row['tnum'],
                        0,
                        $row['ordername'],
                        $row['ordertel'],
                        $row['contacttel'],
                        $row['salerid'],
                        $row['apply_did'],
                        $row['paymode'],
                        $row['ordermode'],
                        $remoteorder,
                        $assembly,
                        $series,
                        1,
                        "0",
                        $orderId
                    );
                }
                if($ar>0&&$ar<100000){
                    $this->log_result($errMsg." outcome:".$ar);
                    return false;
                }
                for($i=1;$i<count($aa_infos);$i++){
                    $row=$aa_infos[$i];
                    if(array_key_exists($row['tid'],$hasTidOrders)){//该主单已经下成功
                        $c_ar=$hasTidOrders[$row['tid']];
                    }else{
                        $c_ar=$this->s->Group_Order_Submit(
                            $row['member'],
                            $row['lid'],
                            $row['tid'],
                            $row['begintime'],
                            $row['endtime'],
                            $row['tprice'],
                            $row['tnum'],
                            0,
                            $row['ordername'],
                            $row['ordertel'],
                            $row['contacttel'],
                            $row['salerid'],
                            $row['apply_did'],
                            $row['paymode'],
                            $row['ordermode'],
                            $remoteorder,
                            $assembly,
                            $series,
                            1,
                            "$ar",
                            $orderId
                        );
                    }
                    if($c_ar>100000||$ar<0){
                        $str="update uu_order_fx_details set concat_id='$ar' where orderid='$c_ar'";
                        $this->db->query($str);
                    }else{//套票下失败记录日志
                        $this->log_result($errMsg." outcome:".$c_ar);
                        return false;
                    }
                    if($i==count($aa_infos)-1){
                        $str="update uu_order_fx_details set concat_id='$ar' where orderid='$ar' limit 1";
                        $this->db->query($str);
                    }
                }
            }
        }catch(\Exception $e){
            $this->log_result($errMsg." outcome:".$e->getMessage());
        }
    }

    /**
     *下单参数验证函数.
     *查看所传入参数是否合法
     *@param array $option 下单参数
     *@param array $p_info 产品信息
     *@throws DisOrderException
     */
    public function orderCheck($option, $p_info){
        $ptitle=$p_info['title'].$p_info['ttitle'];
        $tnum=$option['tnum'];
        $begintime=$option['begintime'];
        if($p_info['buy_limit_low']>0&&$tnum<$p_info['buy_limit_low']){
            throw new DisOrderException($ptitle."购买数少于购买下限".$p_info['buy_limit_low']);
        }
        if($p_info['buy_limit_up']>0&&$tnum>$p_info['buy_limit_up']){
            throw new DisOrderException("购买数不能多于购买上限");
        }
        if($p_info['p_status']==1||$p_info['p_status']==6){
            throw new DisOrderException($ptitle."已删除或已下架");
        }
        $minbegintime=strtotime("+".$p_info['ddays']." days");
        $minbegintime=date("Y-m-d",$minbegintime);

        if($begintime<$minbegintime){
            throw new DisOrderException($ptitle."游玩日期不能小于 $minbegintime");
        }
        if(($begintime==$minbegintime)&&$p_info['dhour']&&date("H:i:s")>$p_info['dhour']){
            throw new DisOrderException($ptitle."您需要在".$p_info['dhour']."前预订");
        }
    }

    /**
     *分销权限查看函数.
     *@param array $proInfos 所有下单产品信息
     *@throws DisOrderException
     */
    public function authCheck($proInfos){
        foreach($proInfos as $key=>$row){
            $p = new ProductInfo($this->s, $row['pid'], $this->db,
                $row['sapply_did']);
            if(!$p->supply($row['member'])){
                throw new DisOrderException("您无权限分销 "
                    .$proInfos[$key]['ltitle']."("
                    .$proInfos[$key]['ttitle'].")");
            }
        }
    }

    /**
     *支付验证函数.
     *查看用户是否有足够余额完成支付，和支付方式的验证.
     *@param int  $totalMoney 总金额
     *@throws DisOrderException
     */
    public function payCheck($totalMoney){
        $paymode=$this->option['paymode'];
        if($paymode==0){//账户余额
            if($this->m->money()<$totalMoney)
                throw new DisOrderException("账户余额不足!");
        }
        elseif($paymode==1){//支付宝
            return true;
        }
        elseif($paymode==2){//供应余额
            $pinfo=$this->p->pInfo();
            $aid=$pinfo['sapply_did'];
            if($this->m->tmoney($aid)<$totalMoney)
                throw new DisOrderException("供应余额不足!");
        }
        elseif($paymode==3){
            $pinfo=$this->p->pInfo();
            if($pinfo['apply_did']!=$this->m->memberID){
                throw new DisOrderException("产品非你供应，无法自我分销!");
            }
        }
        else{
            throw new DisOrderException("支付方式异常!");
        }
    }

    /**
     *产品库存验证函数.
     *查看产品是否有足够库存
     *@param array  $proInfos 所有下单产品信息
     *@throws DisOrderException
     */
    public function storageCheck($proInfos){
        foreach($proInfos as $row){
            if($row['storage']!=-1){//总库存
                $storageXml=$this->s->Dynamic_Storage_Check($row['tid'],2,NULL,$row['storage_open']);
                $storageXml=simplexml_load_string($storageXml);
                $sales=$storageXml->Rec->UUXstr;
                $remain=$row['storage']-$sales;
                if($row['tnum']>$remain){
                    throw new DisOrderException($row['ltitle'].$row['ttitle']." 剩余总库存数不足，剩余 $remain 张门票");
                }
            }
            $pstorage=$this->s->get_Dynamic_Price_Merge($row['pid'],substr($row['begintime'],0,10),1,"","",0,1);
            $pstorage=explode(",",$pstorage);
            $pstorage=$pstorage[1];
            if($pstorage!=-1){//日库存
                $dayxml=$this->s->Dynamic_Storage_Check($row['tid'],1,substr($row['begintime'],0,10));
                $dayxml=simplexml_load_string($dayxml);
                $dayxml=(string)$dayxml->Rec->UUXstr;
                $dayxml=explode("|",$dayxml);
                $remain=$pstorage-$dayxml[1];
                if($row['tnum']>$remain){
                    throw new DisOrderException(substr($row['begintime'],0,10)." ".$row['ltitle'].$row['ttitle']."日库存数不足，剩余 $remain 张门票");
                }
            }
        }
    }

    /**
     *订单额外信息记录函数.
     *记录额外信息，如备注，到店时间，游客信息(姓名和身份证号)
     *@param int $r 订单号
     *@param array $option 包含产品额外信息
     */
    public function appendInfo($r,$option){
        $memo=$option['memo'];
        $origin=$option['origin'];
        if($memo||$origin){
            $str="update uu_order_fx_details set memo='$memo',origin='$origin' where orderid='$r'";
            $this->db->query($str);
        }
        /*酒店到店时间*/
        if($arriveTime=mysql_real_escape_string($option['arriveTime'])){
            $str="update uu_order_fx_details set memo='最迟到店时间：$arriveTime' where orderid='$r' limit 1";
            $this->db->query($str);
        }
        /*记录订单游客信息*/
        $tourists=$option['tourists'];
        $idcards=$option['idcards'];
        if(count($tourists)>0){
            $str="insert into uu_order_tourist_info(orderid,tourist,idcard) values";
            for($i=0;$i<count($tourists);$i++){
                $str.="('".$r."','".$tourists[$i]."','".$idcards[$i]."'),";
            }
            $str=trim($str,",");
            $this->db->query($str);
        }
    }

    /**
     *获得套票产品附属产品下单信息.
     *@param string $attribute json数据，记录产品下单信息
     *@param array $param 下单参数
     *@return array 下单参数数组
     */
    public function aOrderInfo($attribute,$param){
        $attribute=json_decode($attribute,true);
        $tnum=$param['tnum'];
        $begintime=$param['begintime'];
        $endtime=$param['endtime'];
        $ordername=$param['ordername'];
        $ordertel=$param['ordertel'];
        $member=$param['member'];
        $paymode=$param['paymode'];
        $ordermode=$param['ordermode'];
        $a_infos=array();
        foreach($attribute as $row){//套票有效期判定
            $c_pid=$row['pid'];
            $c_tnum=$row['num'];
//            $c_pro=new ProductInfo($this->db, $c_pid,$this->s);
            $c_tprice=$this->p->jsPrice($this->fid, $begintime, $c_pid);
            $c_about=$this->p->pInfo($c_pid);
            $array=array("member"=>$member,
                "tprice"=>$c_tprice,
                "tnum"=>$c_tnum*$tnum,
                "ltitle"=>$c_about['ltitle'],
                "ttitle"=>$c_about['ttitle'],
                "pid"=>$c_pid,
                "lid"=>$c_about['lid'],
                "tid"=>$c_about['tid'],
                "begintime"=>$begintime,
                "endtime"=>$endtime,
                "storage"=>$c_about['storage'],
                "storage_open"=>$c_about['storage_open'],
                "salerid"=>$c_about['salerid'],
                "apply_did"=>$c_about['apply_did'],
                "sapply_did"=>$c_about['sapply_did'],
                "ordername"=>$ordername,
                "ordertel"=>$ordertel,
                "paymode"=>$paymode,
                "ordermode"=>$ordermode
            );
            $a_infos[]=$array;
        }
        return $a_infos;
    }

    /**
     *错误处理函数.
     *抛出对应错误异常
     *@param string $msg 错误信息
     *@param int $code 错误代码
     *@throws Exception|MsgException|InterFaceException
     */
    public function errHandle($msg,$code){
        if($code>100000){
            throw new Exception("不存在大于100000的错误代码");
        }elseif($code<0){
            throw new MsgException($msg,$code);
        }else{
            throw new InterFaceException($msg,$code);
        }
    }

    /**
     *错误记录函数.
     *@param string $msg 错误信息
     *@param path 文件路径
     */
    public static function  log_result($msg,$path="/var/www/html/new/d/logs/log") {
        $fp = fopen($path,"a+");
        flock($fp, LOCK_EX) ;
        fwrite($fp,"执行日期：".date("Y-m-d H:i:s")."=>".$msg."\n");
        flock($fp, LOCK_UN);
        fclose($fp);
    }
}#EOFClASS